package org.example.struct;

import java.util.Arrays;
/**
 * 目录项结构定义
 * 每个目录项占用8字节，用于表示文件或目录
 */
public class DirEntry {
    // 目录项各字段的偏移量和长度
    public static final int ENTRY_SIZE = 8;         // 目录项总大小
    public static final int NAME_OFFSET = 0;        // 文件名偏移
    public static final int NAME_LENGTH = 3;        // 文件名长度
    public static final int EXT_OFFSET = 3;         // 扩展名偏移
    public static final int EXT_LENGTH = 2;          // 扩展名长度
    public static final int ATTR_OFFSET = 5;         // 属性偏移
    public static final int START_BLOCK_OFFSET = 6; // 起始块号偏移
    public static final int LENGTH_OFFSET = 7;      // 文件长度偏移

    // 文件属性位掩码
    public static final byte ATTR_READ_ONLY = 0x01;   // 只读文件
    public static final byte ATTR_SYSTEM = 0x02;       // 系统文件
    public static final byte ATTR_NORMAL = 0x04;       // 普通文件
    public static final byte ATTR_DIRECTORY = 0x08;    // 目录

    private byte[] entryData; // 目录项数据

    /**
     * 创建空目录项
     */
    public DirEntry() {
        entryData = new byte[ENTRY_SIZE];
        // 空目录项的文件名首字符为'$'
        entryData[NAME_OFFSET] = '$';
    }

    /**
     * 从字节数组创建目录项
     * @param data 字节数组(必须至少8字节)
     */
    public DirEntry(byte[] data) {
        if (data.length < ENTRY_SIZE) {
            throw new IllegalArgumentException("数据长度必须至少为 " + ENTRY_SIZE + " 字节");
        }
        entryData = Arrays.copyOf(data, ENTRY_SIZE);
    }

    /**
     * 设置文件名
     * @param name 文件名(最多3字符)
     */
    public void setName(String name) {
        if (name.length() > NAME_LENGTH) {
            throw new IllegalArgumentException("文件名不能超过 " + NAME_LENGTH + " 字符");
        }

        byte[] nameBytes = name.getBytes();
        System.arraycopy(nameBytes, 0, entryData, NAME_OFFSET, Math.min(nameBytes.length, NAME_LENGTH));

        // 填充剩余空间
        for (int i = nameBytes.length; i < NAME_LENGTH; i++) {
            entryData[NAME_OFFSET + i] = ' ';
        }
    }

    /**
     * 获取文件名
     * @return 文件名
     */
    public String getName() {
        return new String(entryData, NAME_OFFSET, NAME_LENGTH).trim();
    }

    /**
     * 设置文件扩展名
     * @param ext 扩展名(最多2字符)
     */
    public void setExtension(String ext) {
        if (ext.length() > EXT_LENGTH) {
            throw new IllegalArgumentException("扩展名不能超过 " + EXT_LENGTH + " 字符");
        }

        byte[] extBytes = ext.getBytes();
        System.arraycopy(extBytes, 0, entryData, EXT_OFFSET, Math.min(extBytes.length, EXT_LENGTH));

        // 填充剩余空间
        for (int i = extBytes.length; i < EXT_LENGTH; i++) {
            entryData[EXT_OFFSET + i] = ' ';
        }
    }

    /**
     * 获取文件扩展名
     * @return 扩展名
     */
    public String getExtension() {
        return new String(entryData, EXT_OFFSET, EXT_LENGTH).trim();
    }

    /**
     * 设置文件属性
     * @param attributes 属性字节
     */
    public void setAttributes(byte attributes) {
        entryData[ATTR_OFFSET] = attributes;
    }

    /**
     * 获取文件属性
     * @return 属性字节
     */
    public byte getAttributes() {
        return entryData[ATTR_OFFSET];
    }

    /**
     * 检查是否是目录
     * @return 是否是目录
     */
    public boolean isDirectory() {
        return (entryData[ATTR_OFFSET] & ATTR_DIRECTORY) != 0;
    }

    /**
     * 设置起始块号
     * @param blockNum 起始块号
     */
    public void setStartBlock(int blockNum) {
        if (blockNum < 0 || blockNum > 255) {
            throw new IllegalArgumentException("块号必须在 0-255 范围内");
        }
        entryData[START_BLOCK_OFFSET] = (byte) blockNum;
    }

    /**
     * 获取起始块号
     * @return 起始块号
     */
    public int getStartBlock() {
        return entryData[START_BLOCK_OFFSET] & 0xFF;
    }

    /**
     * 设置文件长度(以块为单位)
     * @param length 文件长度(块数)
     */
    public void setLength(int length) {
        if (length < 0 || length > 255) {
            throw new IllegalArgumentException("长度必须在 0-255 范围内");
        }
        entryData[LENGTH_OFFSET] = (byte) length;
    }

    /**
     * 获取文件长度(以块为单位)
     * @return 文件长度(块数)
     */
    public int getLength() {
        return entryData[LENGTH_OFFSET] & 0xFF;
    }

    /**
     * 获取目录项的字节表示
     * @return 目录项字节数组
     */
    public byte[] toBytes() {
        return Arrays.copyOf(entryData, ENTRY_SIZE);
    }

    /**
     * 检查是否是空目录项
     * @return 是否是空目录项
     */
    public boolean isEmpty() {
        return entryData[NAME_OFFSET] == '$';
    }

    @Override
    public String toString() {
        return String.format("Name: %s, Ext: %s, Attr: 0x%02X, Start: %d, Length: %d",
                getName(), getExtension(), getAttributes(), getStartBlock(), getLength());
    }
}